package com.plus.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.*;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.plus.common.R;
import com.plus.config.RateLimiter;
import com.plus.constant.LimitType;
import com.plus.dto.UserDTO;
import com.plus.dto.custom.ExportExpert;
import com.plus.dto.custom.TableData;
import com.plus.entity.Whiteip;
import com.plus.service.IUserService;
import com.plus.service.IWhiteipService;
import com.plus.utils.DateUtil;
import com.plus.utils.DownLoadFileUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @program: plus
 * @ClassName WelcomeController
 * @description:欢迎窗口
 * @author: AI
 * @create: 2023-10-31 15:10
 * @Version 1.0
 **/
@RestController
@RequestMapping("/api/welcome")
@Slf4j
public class WelcomeController {



    private static final String SYSPATH = System.getProperty("user.dir");

    @Value("${spring.customConfig.downFilePath}")
    private String downFilePath;

    @Value("${spring.customConfig.staticFilePath}")
    private String staticFilePath;


    //region 构造注入
    private IUserService userService;
    private IWhiteipService whiteipService;

    public WelcomeController(IUserService userService,IWhiteipService whiteipService){
        this.userService = userService;
        this.whiteipService = whiteipService;
    }
    //endregion


    @GetMapping("/hello")
    @ApiOperation(value = "/welcome", notes = "成功启动提示接口")
    @RateLimiter(time = 30,count = 1,limitType = LimitType.IP)
    public R Hello() {
        return R.data("您好，欢迎使用脚手架！");
    }


    /**
     * 批量插入
     * @return
     */
    @GetMapping("/insertBach")
    public R InsertBach(){
        List<Whiteip> list = Stream.of(
                new Whiteip("23432",1),
                new Whiteip("23423",2)
        ).collect(Collectors.toList());
        int cout = whiteipService.insertSelective(list);
        return R.data("批量插入结果："+cout);
    }



    //region word、excel导入导出简单应用
    @GetMapping("/emportWord")
    @ApiOperation(value = "根据word模板导出", notes = "")
    public void EmportWord(HttpServletResponse response) {


        HashMap<String, Object> finalMap = new HashMap<>();
        finalMap.put("ProjectName","2342");
        finalMap.put("PROJECT_CODE","中世e招4楼评标厅");
        finalMap.put("AgentUnit","23423");
        finalMap.put("OwnerUnit","20221321");
        finalMap.put("type","20221321");
        finalMap.put("Budget","20221321");
        finalMap.put("OPEN_TIME","20221321");
        finalMap.put("Is_Allowed_Extract_Same_Unit","20221321");
        finalMap.put("Notice_type","20221321");
        finalMap.put("ExtractTime","20221321");


        ArrayList<Object> workList = CollUtil.newArrayList();
        for (int i = 0; i < 3; i++) {
            // 模拟从mysql查询列表数据
            HashMap<String, Object> workItem = new HashMap<>();
            workItem.put("NAME", i + 1);
            workItem.put("ORG", "四川有限公司" + i);
            workItem.put("ID_CARD", i + 10 + "小时");
            workItem.put("PHONE", "800" + i);
            workItem.put("EXPERT_TYPE_NAME", "项目经理" + i);
            workItem.put("DNAME", "java工程师" + i);
            workList.add(workItem);
        }
        finalMap.put("workList", workList);


        // 插入图片
        try {
            //这里也可以是用文件服务器返回的网络文件流
            String pictureUrl = "http://5b0988e595225.cdn.sohucs.com/images/20171013/fec49f59b98041a4a16886893447f746.jpeg";
            pictureUrl = SYSPATH + "/"+staticFilePath+"/下载.png";
            // 从网络流读取图片，置入word模板，等待编译
            if (Validator.isNotEmpty(pictureUrl)) {
                //PictureRenderData picture = Pictures.ofUrl(pictureUrl).size(40, 30).create();//网络图片地址
                PictureRenderData picture = Pictures.ofLocal(pictureUrl).size(40, 30).create();//本地图片地址
                finalMap.put("signPicture", picture);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


        // 从网络url 下载word模板到指定文件夹
        File wordTemplate = new File(SYSPATH + "/"+staticFilePath +"/专家抽取信息.doc");
        // 此处使用了poi-tl的<表格行循环插件>，此处一定要进行参数bind，方便word模板参数替换
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        Configure build = Configure.builder().bind(policy, "workList").build();
        XWPFTemplate render = XWPFTemplate.compile(wordTemplate, build).render(finalMap);

//        //下载到本地
//        // 此处是利用File，直接在本地创建文件，将参数替换后的文件流写入到该文件，word就是最终的结果
//        File word = new File(systemDir + "/downFile/" + File.separator +
//                IdUtil.getSnowflake(1,1).nextId() + ".docx");
//
//        try {
//            render.writeToFile(word.getAbsolutePath());
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }

        // 指定下载的文件名--设置响应头
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("附件1-报价明细表.docx", "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        try {
            OutputStream out = response.getOutputStream();
            BufferedOutputStream bos = new BufferedOutputStream(out);
            render.write(out);
            bos.flush();
            out.flush();
            render.close();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    @GetMapping("/emportExcel")
    @ApiOperation(value = "根据Excel模板导出", notes = "")
    public void EmportExcel(HttpServletResponse response) {

        try {

            List<ExportExpert> list = new ArrayList<>();
            for (int k=1;k<10;k++) {

                ExportExpert expert = ExportExpert.builder()
                        .ID(String.valueOf(k))
                        .DEPARTID("部门ID"+k)
                        .xm("名称"+k)
                        .czd("常驻地"+k)
                        .ggzypspm("公共资源评审品目"+k)
                        .zfcgpspm("政府采购评审品目"+k)
                        .zcyxrq("职称有效日期"+k)
                        .lxdh("电话"+k)
                        .sflrhmd("是否列入黑名单"+k)
                        .ggzyzjly("公共资源专家来源"+k)
                        .zfcgzjly("政府采购专家来源"+k)
                        .zjlx2("证件类型"+k)
                        .zczy("职称专业"+k)
                        .zcjb("职称级别"+k)
                        .xb("性别"+k)
                        .zjlx("专家类型"+k)
                        .zjhm("身份证"+k)
                        .zzqk("在职情况"+k)
                        .gzdw("工作单位"+k)
                        .xhbddqtyq("需回避的其他单位"+k)
                        .sfkcq("是否可抽取"+k)
                        .zjbm("专家编码"+k)
                        .build();
                list.add(expert);
            }
            //endregion


            String fileName = DateUtil.convertLocalDateTimeToString(LocalDateTime.now(),"yyyyMMddHHmmss") + ".xls";
            String path = SYSPATH + "/" + downFilePath  +"/"+ fileName;
            File file = new File(path);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }

            // 写法1 JDK8+
            // 这里 需要指定写用哪个class去写，然后写到第一个sheet，名字为模板 然后文件流会自动关闭
            // 如果这里想使用03 则 传入excelType参数即可
            EasyExcel.write(path, ExportExpert.class)
                    .sheet("导出内容")
                    .doWrite(() -> {
                        // 分页查询数据
                        return list;
                    });

            DownLoadFileUtil.downloadFile(response,path,fileName,true);
            //endregion
        } catch (Exception e) {
            e.printStackTrace();
        }

    }



    @GetMapping("/emportTable")
    @ApiOperation(value = "根据word模板导出表格和列表", notes = "")
    public void EmportTable(HttpServletResponse response) {
        TableData tableData = new TableData();
        /* 假数据 */
        tableData.setTitle("报价明细表");
        String[][] strings = new String[20][5];
        for (int i = 0; i < 20; i++) {
            strings[i] = new String[]{String.valueOf(i+1), "EREWHON"+i, "鸡蛋"+i, "维生素"+i, "675"+i};
        }
        tableData.setTableList(strings);

        // 模版路径
        String systemDir = System.getProperty("user.dir");
        String wordPath = systemDir + "/"+staticFilePath + "/";
        String modelName = "表格.docx";

        // 手绘表格
        // 表头
        RowRenderData row0 = Rows.of("项号", "编号", "种类", "", "价格").center().create();
        RowRenderData row1 = Rows.of("项号", "编号", "蛋白质", "微量元素", "价格").center().create();

        int length = 0;
        if (tableData.getTableList() != null) {
            length = tableData.getTableList().length;
        }
        // 表格数据 加上2行表头 再加上最后一行总价
        RowRenderData[] rowRenderData = new RowRenderData[length + 3];
        rowRenderData[0] = row0;
        rowRenderData[1] = row1;
        // 计算价钱
        BigDecimal totalPrice = new BigDecimal("0");
        for (int i = 0; i < length; i++) {
            rowRenderData[i + 2] = Rows.of(tableData.getTableList()[i]).center().create();
            String s = tableData.getTableList()[i][4];
            BigDecimal bigDecimal = new BigDecimal(s);
            totalPrice = totalPrice.add(bigDecimal);
        }

        RowRenderData row4 = Rows.of("总价", "", "", "", totalPrice.toString()).center().create();
        rowRenderData[rowRenderData.length - 1] = row4;
        // 表格合并,根据坐标
        MergeCellRule rule = MergeCellRule.builder().map(MergeCellRule.Grid.of(0, 0), MergeCellRule.Grid.of(1, 0)).
                map(MergeCellRule.Grid.of(0, 1), MergeCellRule.Grid.of(1, 1)).
                map(MergeCellRule.Grid.of(0, 2), MergeCellRule.Grid.of(0, 3)).
                map(MergeCellRule.Grid.of(0, 4), MergeCellRule.Grid.of(1, 4)).
                map(MergeCellRule.Grid.of(rowRenderData.length - 1, 0), MergeCellRule.Grid.of(rowRenderData.length - 1, 3)).
                build();

        TableRenderData table = Tables.of(rowRenderData).mergeRule(rule).create();
        // 数据封装
        tableData.setTable(table);





        //插入列表
        // 注意：此处用的是 <区块对> key是字符串，value则放置一个集合，类似于模板引擎的foreach标签
        ArrayList<Object> stateList = CollUtil.newArrayList();
        // 模拟从mysql查询数据，改造为word模板所需的数据结构
        List<String> stateListFromMySQL = Arrays.asList("本人所递交的所有办理人才引进材料及填写的情况均属实；"
                , "我已认真阅读以上内容并确认；"
                , "若在申请期间信息变更不做变更。若违反，本人愿意承担由此产生的后果。");
        for (int i = 0; i < stateListFromMySQL.size(); i++) {
            HashMap<String, Object> stateItem = new HashMap<>();
            stateItem.put("item", stateListFromMySQL.get(i) + "");
            stateList.add(stateItem);
        }
        tableData.setItemList(stateList);

        // 传入模板模板地址+信息数据
        XWPFTemplate render = XWPFTemplate.compile(wordPath + modelName).render(tableData);

//        //下载到本地
//        // 此处是利用File，直接在本地创建文件，将参数替换后的文件流写入到该文件，word就是最终的结果
//        File word = new File(systemDir + "/downFile/" + File.separator +
//                IdUtil.getSnowflake(1,1).nextId() + ".docx");
//
//        try {
//            render.writeToFile(word.getAbsolutePath());
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }

        // 指定下载的文件名--设置响应头
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("附件1-报价明细表.docx", "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        try {
            OutputStream out = response.getOutputStream();
            BufferedOutputStream bos = new BufferedOutputStream(out);
            render.write(out);
            bos.flush();
            out.flush();
            render.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 导入
     */
    @RequestMapping("/import")
    @ApiOperation(value = "导入", notes = "传入文件")
    public R Import(@RequestParam MultipartFile file) throws IOException {


        InputStream inputStream = file.getInputStream();

        //		// 写法1：JDK8+ ,不用额外写一个DemoDataListener
//		// since: 3.0.0-beta1
//		String fileName = "demo.xlsx";
//		// 这里默认每次会读取100条数据 然后返回过来 直接调用使用数据就行
//		// 具体需要返回多少行可以在`PageReadListener`的构造函数设置
//		EasyExcel.read(inputStream, UserDTO.class, new PageReadListener<UserDTO>(dataList -> {
//			userService.saveBatch(dataList);
//		})).sheet().doRead();

        // 写法2：
        // 匿名内部类 不用额外写一个DemoDataListener
        //String fileName = systemDir + "/staticfile/工作簿.xlsx";
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(inputStream, UserDTO.class, new ReadListener<UserDTO>() {
            /**
             * 单次缓存的数据量
             */
            public static final int BATCH_COUNT = 100;
            /**
             *临时存储
             */
            private List<UserDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

            @Override
            public void invoke(UserDTO data, AnalysisContext context) {
                cachedDataList.add(data);
                if (cachedDataList.size() >= BATCH_COUNT) {
                    saveData();
                    // 存储完成清理 list
                    cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                saveData();
            }

            /**
             * 加上存储数据库
             */
            private void saveData() {
                log.info("{}条数据，开始存储数据库！", cachedDataList.size());
                userService.saveBatch(cachedDataList);
            }
        }).sheet().doRead();





        return R.data("");
    }
    //endregion




//    /**
//     * 发送消息接口
//     * 发送queue消息 ：http://localhost:8899/api/welcome/active/send?msg=ceshi1234
//     * 发送topic 消息： http://localhost:8899/api/welcome/topic/send?msg=ceshi1234
//     * 发送queue消息(延迟time毫秒) ：http://localhost:8899/api/welcome/active/send?msg=ceshi1234&time=5000
//     *
//     * @param msg  消息
//     * @param type url中参数,非必须
//     * @param time
//     * @return
//     */
//    @RequestMapping({"/send", "/{type}/send"})
//    public String send(@PathVariable(value = "type", required = false) String type, String msg, Long time) {
//
//        String name1 = "active.queue.test";//这个队列名称可以换，但是换了之后监听的队列名称也要一致
//        String name2 = "active.topic.test";//这个队列名称可以换，但是换了之后监听的队列名称也要一致
//
//        if("active".equals(type)){
//
//            boolean flag = ActivemqUtil.SendMQ(type,name1,msg,time);
//            return "activemq消息发送成功 队列消息：" + flag;
//        }else {
//            boolean flag = ActivemqUtil.SendMQ(type,name2,msg,time);
//            return "activemq消息发送成功 队列消息：" + flag;
//        }
//
//
//    }

}
